/*
 *Copyright 2021-2023 NERCIS
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 */

/*
 *Copyright 2021-2023 NERCIS
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 */

package cn.ac.nercis.pes.community.utils;

import cn.ac.nercis.pes.common.constant.common.BaseConstants;
import cn.ac.nercis.pes.community.component.dialog.MessageDialog;
import cn.ac.nercis.pes.community.component.dialog.MessageType;
import cn.ac.nercis.pes.service.utils.DocServerUtils;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.StackPane;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.concurrent.ExecutorService;

/**
 * 应用辅助功能
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
public final class AppUtils {
    private final static String FILE_START_TAG = "file:";
    private final static String JAR_FILE_TAG = ".jar";
    private final static String EXE_FILE_TAG = ".exe";
    private final static Integer DOC_SERVER_START_WAIT = 2000;
    private final static BooleanProperty ENABLE_DOC_SERVER = new SimpleBooleanProperty(false);
    private static Process docServerProcess = null;
    private AppUtils(){}

    public static String getExecutiveBasePath(){
        String path = AppUtils.class.getProtectionDomain().getCodeSource().getLocation().getPath();
        if (StringUtils.isBlank(path)) {
            return FileUtils.getUserDirectoryPath();
        }
        try{
            String jarPath = URLDecoder.decode(path.replace("+", "%2B"),
                    StandardCharsets.UTF_8.displayName());
            if (jarPath.startsWith(FILE_START_TAG)) {
                jarPath = jarPath.substring(FILE_START_TAG.length());
            }
            if (jarPath.contains(JAR_FILE_TAG)) {
                jarPath = jarPath.substring(0, jarPath.indexOf(JAR_FILE_TAG));
            }
            if (jarPath.contains(EXE_FILE_TAG)) {
                jarPath = jarPath.substring(0, jarPath.indexOf(EXE_FILE_TAG));
            }
            return new File(jarPath).getParentFile().getPath();
        }catch (IOException e){
            return FileUtils.getUserDirectoryPath();
        }
    }

    public static void openFile(String filePath){
        try {
            if (SystemUtils.isWindowOs()) {
                Runtime.getRuntime().exec("explorer /select,".concat(filePath));
            }
        }catch (IOException ex){
            log.warn("打开文件失败：",ex);
        }
    }

    public static void copyClipboard(String content) {
        if (StringUtils.isNotBlank(content)) {
            content = content.replaceAll(BaseConstants.REGEX_WRAP_TEXT_SPLIT, BaseConstants.NEW_LINE);
        }
        ClipboardContent clipboardContent = new ClipboardContent();
        clipboardContent.putString(content);
        Clipboard.getSystemClipboard().setContent(clipboardContent);
    }

    public static void showMessageDialog(String msg, MessageType type, StackPane container){
        MessageDialog.builder()
                .withType(type)
                .withMessage(msg)
                .withContainer(container)
                .build()
                .show();
    }

    public static void checkAndStartDocServer(){
        if(!ENABLE_DOC_SERVER.get()){
            return;
        }
        var startThread = new Thread(AppUtils::startDocServer);
        startThread.setDaemon(false);
        startThread.start();
    }

    private static void startDocServer(){
        boolean connect = DocServerUtils.testConnect();
        if(connect){
            return;
        }
        var processBuilder = DocServerUtils.startDocServer();
        if(Objects.isNull(processBuilder)){
            log.warn("未找到文档生成服务启动程序！");
            return;
        }
        try{
            docServerProcess = processBuilder.start();
            Thread.sleep(DOC_SERVER_START_WAIT);
            connect = DocServerUtils.testConnect();
            if(connect){
                log.info("文档生成服务启动成功！");
            }
        }catch (IOException | InterruptedException ex){
            log.error("启动文档生成服务出错：",ex);
        }
    }

    public static void exitDocServer(){
        if(!ENABLE_DOC_SERVER.get()){
            return;
        }
        try{
            if(DocServerUtils.isConnect() && Objects.nonNull(docServerProcess)){
                var handle = docServerProcess.toHandle();
                handle.destroy();
                handle.descendants().forEach(ProcessHandle::destroy);
            }
        }catch (Exception ex){
            log.error("结束文档生成服务进程失败：",ex);
        }
    }

    public static void exitApp(){
        var executor =  SpringUtils.getBean(ExecutorService.class);
        executor.shutdownNow();
        exitDocServer();
        AppStore.close();
        GuiStore.getStage().close();
        SpringUtils.getApplicationContext().close();
        Platform.exit();
    }
}
